为什么需要 Tab 间通信
在管理后台等单页应用中,用户可能同时打开多个浏览器标签页。常见需求包括:
- 登录状态同步:在一个 Tab 中登录后,其他 Tab 自动更新状态
- 主题偏好同步:修改暗黑模式/语言设置后,所有 Tab 同步生效
- 音乐播放器:在一个 Tab 控制播放,另一个 Tab 显示状态
- 大屏数据展示:多个屏幕展示不同的图表,数据需要实时同步
本文排除依赖服务端的方案(WebSocket、轮询),只讨论纯浏览器端的通信方式。
方案一:localStorage + storage 事件
原理:当一个 Tab 修改 localStorage 时,同源的其他 Tab 会触发 storage 事件。
接收端:
window.addEventListener('storage', (event) => {
console.log('收到消息:', event)
// event.key - 修改的键名
// event.newValue - 新值
// event.oldValue - 旧值
// event.url - 触发修改的页面 URL
})
javascript
发送端:
localStorage.setItem('message', 'hello from other tab')
javascript
适用场景:简单的状态同步,如登录状态、主题偏好、用户设置。
特点:
- 只在同源页面间有效
- 触发事件的 Tab 自身不会收到通知,只有其他 Tab 能收到
- 存储容量约 5MB
- 数据持久化,即使关闭浏览器也不丢失
方案二:BroadcastChannel API
原理:通过创建命名通道,在相同源的不同标签页、iframe、Service Worker 之间进行消息广播。
创建通道(发送端):
// 发送端 - 在某个页面的 onMounted 中
const channel = new BroadcastChannel('channel_name')
// 发送消息
channel.postMessage('hello from tab')
javascript
接收消息(接收端):
// 接收端 - 在另一个页面
const channel = new BroadcastChannel('channel_name')
channel.onmessage = (event) => {
console.log('收到消息:', event)
}
javascript
适用场景:消息传递、状态同步、Tab 间实时通知。
特点:
- 同源限制
- 没有明确的发送者和接收者角色划分,开发者自行设计
- 需要自己设计消息格式和处理机制
- 浏览器兼容性良好(IE 不支持)
方案三:window.postMessage(跨域通信)
原理:通过 window.open 获取新窗口的引用,使用 postMessage 进行跨域通信。
从新页面发送消息到原页面
原页面(接收端):
window.addEventListener('message', (event) => {
// 安全校验:只接收来自指定源的消息
if (event.origin !== 'http://toimc.cn:5173') return
console.log('收到消息:', event.data)
})
javascript
新页面(发送端):
// window.opener 指向打开当前页面的原窗口
if (window.opener) {
window.opener.postMessage('hello from other tab', '*')
// 第二个参数指定目标源,'*' 表示发送给所有源
// 安全做法:指定具体源如 'http://localhost:5173'
}
javascript
从原页面发送消息到新页面
// 原页面打开新 Tab
const newPage = window.open('http://toimc.cn:5173/login')
// 等待新页面加载完成后发送消息
setTimeout(() => {
if (newPage && newPage.postMessage) {
newPage.postMessage('hello from old tab', '*')
}
}, 5000) // 留出足够时间让新页面加载完成
javascript
适用场景:跨域 Tab 间通信、OAuth 认证回调、第三方登录弹窗。
特点:
- 支持跨域通信
- 必须通过
window.open建立窗口引用关系 - 第二个参数(targetOrigin)应尽量指定具体源而非
*,避免安全风险 - 新页面通过
window.opener访问原页面
方案四:SharedWorker
SharedWorker 是一种可以被多个浏览器上下文(Tab、iframe 等)共享的 Worker,适合做 Tab 间的消息中转站。详细的 SharedWorker 方案在后续章节展开。
方案对比
| 方案 | 同源要求 | 跨域支持 | 持久化 | 复杂度 | 典型场景 |
|---|---|---|---|---|---|
| localStorage | 必须 | 不支持 | 持久化 | 低 | 登录状态、主题同步 |
| BroadcastChannel | 必须 | 不支持 | 不持久化 | 低 | 实时消息广播 |
| postMessage | 不限 | 支持 | 不持久化 | 中 | 跨域通信、OAuth |
| SharedWorker | 必须 | 不支持 | 不持久化 | 高 | 复杂状态共享 |
选择建议:
- 同源简单状态同步 ->
localStorage - 同源实时消息 ->
BroadcastChannel - 跨域通信 ->
postMessage - 复杂共享逻辑 ->
SharedWorker
↑